from tkinter import *
from tkinter import ttk, font, filedialog as fd
import shutil, os, ctypes, pyglet
from fractions import Fraction
from PIL import ImageTk, Image, ImageOps, ImageDraw, ImageFont
import Program
import Recipes_frame

class View_recipe_frame(Frame):
    """
    Purpose:
        Frame to handle viewing more information about a specific recipe
    Instance variables:
        self.current_recipe: name of current recipe being displayed
        self.top_frame: frame that shows recipe name, ingredients and an image
        self.image_label: label that display the image of a recipe
        self.top_left_frame: frame for recipe name and ingredients
        self.title_label: displays the name of recipe
        self.ingredients_label: label displaying "Ingredients"
        self.ingredients_list_frame: frame for displaying ingredients list
        self.ingredients_list_canvas: canvas used to display the ingredients
            list. A canvas is used to be able to scroll with a label
        self.ingredients_list_canvas_frame: frame to place the label on in the canvas
        self.ingredients_vert_scrollbar: vertical scroll bar to scroll the
            ingredients list label
        self.ingredients_hori_scrollbar: horizontal scroll bar to scroll the
            ingredients list label
        self.middle_frame: frame to display recipe instructions
        self.instructions_label: label that displays "Instructions"
        self.instructions_text_frame: frame to place the instructions canvas in
        self.instructions_text_canvas: canvas for the instructions label to
            be able to scroll
        self.instructions_text_scrolling_frame: frame inside canvas to place
            the instructions label in
        self.instructions_text: label displaying recipe instructions
        self.instructions_text_scrollbar: scrollbar allowing vertical
            scrolling of the instructions label
        self.lower_frame: frame containing cost of recipe, copy button, and back button.
        self.cost_label: label displaying "Cost:"
        self.cost_of_recipe_label: label displaying cost of recipe
        self.copy_text_button: copies the recipe to the clipboard
        self.back_button: returns to the search recipes frame
        self.temp_frame: frame to place the ingredients on, this gets
            deleted and remade
        self.copy_menu: menu to copy ingredients or instructions of the recipe
    Methods:
        set_page_to_recipe: updates the page to display a recipe
        create_ingredients_labels: creates labels to display ingredients in
            the recipe
        bind_mousewheel: creates binding to allow scrolling with mouse wheel
            in instructions and ingredients
        unbind_mousewheel: unbinds bindings to stop controlling label and
            ingredients scrolling with the mouse
        on_mousewheel_vert: handles what happens with vertical scrolling
        on_mousewheel_hori: handles what happens with horizontal scrolling
        show_popup: shows the copy menu
        set_image: handles displaying the correctly sized image of recipe
        resize_image: keeps the image of recipe but resizes it to fit new
            screen size
        update_instructions_word_wrap: changes the word warp of the
            instructions label to be the width of the window
    """

    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.current_recipe = None
        self.rowconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
        self.columnconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1, uniform="equal")
        self.grid_rowconfigure(1, weight=1, uniform="equal")
        self.top_frame = Frame(self)
        self.top_frame.grid(row=0, column=0, sticky="nsew")
        self.top_frame.rowconfigure(0, weight=1)
        self.top_frame.columnconfigure(0, weight=1, uniform="equal")
        self.top_frame.columnconfigure(1, weight=1, uniform="equal")
        self.image_label = Label(self.top_frame)
        self.image_label.grid(row=0, column=1, sticky="nsew")
        self.top_left_frame = Frame(self.top_frame)
        self.top_left_frame.grid(row=0, column=0, sticky="nw")
        self.top_left_frame.columnconfigure(0, weight=1)
        self.top_left_frame.rowconfigure(0, weight=0)
        self.top_left_frame.rowconfigure(1, weight=0)
        self.top_left_frame.rowconfigure(2, weight=1)
        self.title_label = Label(self.top_left_frame, font=Program.Program.resizing_title_font)
        self.title_label.grid(row=0, column=0, sticky="w")
        self.ingredients_label = Label(
            self.top_left_frame,
            text="Ingredients",
            borderwidth=1,
            relief="solid",
            font=Program.Program.resizing_pantry_font,
        )
        self.ingredients_label.grid(row=1, column=0, sticky="w")
        self.ingredients_list_frame = Frame(self.top_left_frame)
        self.ingredients_list_frame.grid_rowconfigure(0, weight=1)
        self.ingredients_list_frame.grid_columnconfigure(0, weight=1)
        self.ingredients_list_frame.grid_columnconfigure(1, weight=1)
        self.ingredients_list_frame.grid(row=2, column=0, sticky="nw")
        self.ingredients_list_canvas = Canvas(self.ingredients_list_frame)
        self.ingredients_list_canvas.grid(row=0, column=0, sticky="ew")
        self.ingredients_list_canvas_frame = Frame(self.ingredients_list_canvas)

        self.ingredients_vert_scrollbar = Scrollbar(self.ingredients_list_frame)
        self.ingredients_vert_scrollbar.grid(row=0, column=1, sticky="ns")
        self.ingredients_vert_scrollbar.config(
            command=self.ingredients_list_canvas.yview
        )
        self.ingredients_hori_scrollbar = Scrollbar(
            self.ingredients_list_frame, orient="horizontal"
        )
        self.ingredients_hori_scrollbar.grid(row=1, column=0, sticky="ew")
        self.ingredients_hori_scrollbar.config(
            command=self.ingredients_list_canvas.xview
        )
        self.ingredients_list_canvas.config(
            yscrollcommand=self.ingredients_vert_scrollbar.set,
            xscrollcommand=self.ingredients_hori_scrollbar.set,
        )
        self.ingredients_list_canvas.create_window(
            (0, 0), anchor="nw", window=self.ingredients_list_canvas_frame
        )
        self.ingredients_list_canvas_frame.bind(
            "<Enter>",
            lambda event: self.bind_mousewheel(
                event, self.ingredients_list_canvas, self.copy_ingredients_string
            ),
        )
        self.ingredients_list_canvas_frame.bind(
            "<Leave>",
            lambda event: self.unbind_mousewheel(event, self.ingredients_list_canvas),
        )
        self.middle_frame = Frame(self)
        self.middle_frame.grid(row=1, column=0, sticky="nsew")
        self.instructions_label = Label(
            self.middle_frame,
            text="Instructions",
            borderwidth=1,
            relief="solid",
            font=Program.Program.resizing_pantry_font,
        )
        self.instructions_label.pack(anchor="nw")
        self.instructions_text_frame = Frame(self.middle_frame)
        self.instructions_text_frame.pack()
        self.instructions_text_frame.grid_rowconfigure(0, weight=1)
        self.instructions_text_frame.grid_columnconfigure(0, weight=1)
        self.instructions_text_frame.grid_columnconfigure(1, weight=1)
        self.instructions_text_canvas = Canvas(self.instructions_text_frame)
        self.instructions_text_canvas.grid(row=0, column=0, sticky="ew")
        self.instructions_text_scrolling_frame = Frame(self.instructions_text_canvas)
        self.instructions_text = Label(
            self.instructions_text_scrolling_frame,
            font=Program.Program.resizing_pantry_font,
            justify="left",
        )
        self.instructions_text.pack(anchor="nw")
        self.instructions_text_scrollbar = Scrollbar(self.instructions_text_frame)
        self.instructions_text_scrollbar.grid(row=0, column=1, sticky="nsew")
        self.instructions_text_scrollbar.config(
            command=self.instructions_text_canvas.yview
        )
        self.instructions_text_canvas.config(
            yscrollcommand=self.instructions_text_scrollbar.set
        )
        self.instructions_text_canvas.create_window(
            (0, 0), anchor="nw", window=self.instructions_text_scrolling_frame
        )
        self.instructions_text_scrolling_frame.bind(
            "<Enter>",
            lambda event: self.bind_mousewheel(
                event,
                self.instructions_text_canvas,
                self.instructions_text.cget("text"),
            ),
        )
        self.instructions_text_scrolling_frame.bind(
            "<Leave>",
            lambda event: self.unbind_mousewheel(event, self.instructions_text_canvas),
        )
        self.lower_frame = Frame(self)
        self.lower_frame.grid(row=2, column=0, pady=(0, 20))
        self.lower_frame.rowconfigure(0, weight=1)
        self.lower_frame.columnconfigure(0, weight=1)
        self.lower_frame.columnconfigure(1, weight=1)
        self.lower_frame.columnconfigure(2, weight=1)
        self.lower_frame.columnconfigure(3, weight=1)
        self.cost_label = Label(self.lower_frame, text="Cost:")
        self.cost_label.grid(row=0, column=0)
        self.cost_of_recipe_label = Label(self.lower_frame)
        self.cost_of_recipe_label.grid(row=0, column=1)
        self.copy_text_button = Button(self.lower_frame, text="Copy Recipe")
        self.copy_text_button.grid(row=0, column=2, padx=5)
        self.back_button = Button(
            self.lower_frame,
            text="Back",
            command=lambda: Program.Program.controller.change_frames(Recipes_frame.Recipes_frame),
        )
        self.back_button.grid(row=0, column=3, padx=5)

        self.temp_frame = None

        self.copy_menu = Menu(self, tearoff=0)
        self.copy_menu.add_command(label="Copy")

    def set_page_to_recipe(self, recipe_name, missing_ingredients_set):
        recipe = Program.Program.search_recipe_name(recipe_name)
        self.title_label.config(text=recipe_name)
        self.create_ingredients_labels(recipe, missing_ingredients_set)
        self.instructions_text.config(text=recipe.instructions)
        self.cost_of_recipe_label.config(text=f"${recipe.cost:0.2f}")
        self.set_image(recipe_name)
        self.copy_text_button.config(
            command=lambda: (
                self.clipboard_clear(),
                self.clipboard_append(
                    f"{self.title_label.cget('text')}\nIngredients:\n{self.copy_ingredients_string}\nInstructions:\n{self.instructions_text.cget('text')}\nCost: {self.cost_of_recipe_label.cget('text')}"
                ),
                self.update(),
            )
        )
        self.update()
        self.ingredients_list_canvas.config(
            scrollregion=self.ingredients_list_canvas.bbox("all")
        )
        self.instructions_text_canvas.config(
            scrollregion=self.instructions_text_canvas.bbox("all")
        )

    def create_ingredients_labels(self, recipe, missing_ingredients_set):
        if self.temp_frame != None:
            self.temp_frame.destroy()
        self.label_dict = {}
        self.copy_ingredients_string = ""
        self.temp_frame = Frame(self.ingredients_list_canvas_frame)
        self.temp_frame.pack(anchor="nw", expand=True, fill="both")
        self.temp_frame.config(bg=self.ingredients_label["bg"])
        recipe_ingredients_dict = recipe.ingredients
        if missing_ingredients_set == None:
            missing_ingredients_set = recipe_ingredients_dict.keys()
        present_ingredients_set = (
            set(recipe_ingredients_dict.keys()) - missing_ingredients_set
        )
        sorted_present_ingredients_list = sorted(list(present_ingredients_set))
        sorted_missing_ingredients_list = sorted(list(missing_ingredients_set))
        for ingredient in sorted_present_ingredients_list:
            self.label_dict[ingredient] = Label(
                self.temp_frame,
                bg=self.ingredients_label["bg"],
                fg=self.ingredients_label["fg"],
                text=f"•{ingredient}: {Program.Program.convert_float_to_string(recipe_ingredients_dict[ingredient][0])} {recipe_ingredients_dict[ingredient][1]}",
                font=Program.Program.resizing_pantry_font,
            )
            self.label_dict[ingredient].pack(anchor="nw")
            self.copy_ingredients_string = (
                self.copy_ingredients_string
                + "\n"
                + self.label_dict[ingredient].cget("text")
            )
        red_text_color = (
            Program.Program.convert_rgb_to_hex(
                Program.Program.overlay_colors(
                    Program.Program.convert_hex_to_rgb("#CD5C5C"),
                    Program.Program.convert_hex_to_rgb("#000000"),
                    0.87,
                )
            ),
        )
        for ingredient in sorted_missing_ingredients_list:
            self.label_dict[ingredient] = Label(
                self.temp_frame,
                fg=red_text_color,
                bg="#CD5C5C",
                text=f"•{ingredient}: {Program.Program.convert_float_to_string(recipe_ingredients_dict[ingredient][0])} {recipe_ingredients_dict[ingredient][1]}",
                font=Program.Program.resizing_pantry_font,
            )
            self.label_dict[ingredient].pack(anchor="nw")
            self.copy_ingredients_string = (
                self.copy_ingredients_string
                + "\n"
                + self.label_dict[ingredient].cget("text")
            )
        self.copy_ingredients_string = self.copy_ingredients_string[1:]

    def bind_mousewheel(self, event, canvas, text_to_copy):
        canvas.bind_all(
            "<MouseWheel>", lambda event: self.on_mousewheel_vert(event, canvas)
        )
        canvas.bind_all(
            "<Shift-MouseWheel>", lambda event: self.on_mousewheel_hori(event, canvas)
        )
        canvas.bind_all("<Button-3>", lambda event: self.show_popup(event))
        self.copy_menu.entryconfig(
            0,
            command=lambda: (
                self.clipboard_clear(),
                self.clipboard_append(text_to_copy),
                self.update(),
            ),
        )

    def unbind_mousewheel(self, event, canvas):
        canvas.unbind_all("<MouseWheel>")
        canvas.unbind_all("<Shift-MouseWheel>")
        canvas.unbind_all("<Button-3>")

    def on_mousewheel_vert(self, event, canvas):
        canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

    def on_mousewheel_hori(self, event, canvas):
        canvas.xview_scroll(int(-1 * (event.delta / 120)), "units")

    def show_popup(self, event):
        try:
            self.copy_menu.tk_popup(event.x_root, event.y_root)
        finally:
            self.copy_menu.grab_release()

    def set_image(self, recipe_name):
        try:
            if self.current_recipe != recipe_name:
                if "#" in self.image_label["bg"]:
                    color = self.image_label["bg"].upper()
                else:
                    color = "#FFFFFF"
                color_rgb = Program.Program.convert_hex_to_rgb(color)
                self.current_recipe = recipe_name
                self.path = f"images\\{recipe_name}.png"
                self.image_of_recipe = Image.open(self.path)
                self.rounded_corner_overlay = Image.new(
                    "RGBA",
                    (
                        self.image_of_recipe.width,
                        self.image_of_recipe.height,
                    ),
                    "#FFFFFF00",
                )
                self.rounded_corner_overlay_draw = ImageDraw.Draw(
                    self.rounded_corner_overlay
                )
                self.rounded_corner_overlay_draw.rounded_rectangle(
                    (
                        0,
                        0,
                        self.image_of_recipe.width,
                        self.image_of_recipe.height,
                    ),
                    outline=color + "FF",
                    width=3,
                    radius=22,
                )
                ImageDraw.floodfill(
                    self.rounded_corner_overlay,
                    xy=(1, 1),
                    value=tuple(list(color_rgb) + [255]),
                    thresh=200,
                )
                ImageDraw.floodfill(
                    self.rounded_corner_overlay,
                    xy=(self.image_of_recipe.width - 1, 1),
                    value=tuple(list(color_rgb) + [255]),
                    thresh=200,
                )
                ImageDraw.floodfill(
                    self.rounded_corner_overlay,
                    xy=(
                        self.image_of_recipe.width - 1,
                        self.image_of_recipe.height - 1,
                    ),
                    value=tuple(list(color_rgb) + [255]),
                    thresh=200,
                )
                ImageDraw.floodfill(
                    self.rounded_corner_overlay,
                    xy=(1, self.image_of_recipe.height - 1),
                    value=tuple(list(color_rgb) + [255]),
                    thresh=200,
                )
                self.image_of_recipe = Image.alpha_composite(
                    self.image_of_recipe, self.rounded_corner_overlay
                )
                # self.image_of_recipe.show()

            self.final_width = self.top_frame.winfo_width() // 2
            self.final_height = self.top_frame.winfo_height()
            self.image_of_recipe_resized = ImageOps.contain(
                self.image_of_recipe, (self.final_width, self.final_height)
            )
            # self.image_of_recipe_resized.show()
            self.image_of_recipe_tkinter = ImageTk.PhotoImage(
                self.image_of_recipe_resized
            )
            self.image_label.config(image=self.image_of_recipe_tkinter)
            self.image_label.bind(
                "<Double-Button-1>", lambda event: os.startfile(self.path)
            )
        except:
            self.image_of_recipe = None
            self.image_label.config(image="")
            self.image_label.unbind("<Double-Button-1>")

    def resize_image(self):
        self.set_image(self.title_label.cget("text"))

    def update_instructions_word_wrap(self):
        self.instructions_text_canvas.config(
            width=self.middle_frame.winfo_width() - 30,
        )
        self.ingredients_list_canvas.config(
            width=self.middle_frame.winfo_width() / 2 - 30,
        )
        self.instructions_text.config(wraplength=self.middle_frame.winfo_width() - 30)

    def change_colors(self, bg_color, primary_color, primary_variant, secondary_color):
        elevation_1_color = Program.Program.convert_rgb_to_hex(
            Program.Program.overlay_colors(
                Program.Program.convert_hex_to_rgb(bg_color), (255, 255, 255), 0.05
            )
        )
        if Program.Program.light_mode:
            button_text_color = "#FFFFFF"
            label_color = Program.Program.convert_rgb_to_hex(
                Program.Program.overlay_colors(
                    Program.Program.convert_hex_to_rgb(elevation_1_color), (0, 0, 0), 0.87
                )
            )
        else:
            button_text_color = "#000000"
            label_color = Program.Program.convert_rgb_to_hex(
                Program.Program.overlay_colors(
                    Program.Program.convert_hex_to_rgb(elevation_1_color), (255, 255, 255), 0.87
                )
            )

        self.config(bg=bg_color)
        self.top_frame.config(bg=bg_color)
        self.top_left_frame.config(bg=bg_color)
        self.title_label.config(bg=elevation_1_color, fg=label_color)
        self.ingredients_label.config(bg=elevation_1_color, fg=label_color)
        self.ingredients_list_canvas.config(
            bg=elevation_1_color, borderwidth=1, relief="solid", highlightthickness=0
        )
        self.ingredients_list_frame.config(bg=elevation_1_color)
        self.ingredients_list_canvas_frame.config(bg=elevation_1_color)

        self.image_label.config(bg=elevation_1_color, borderwidth=1, relief="solid")
        self.instructions_label.config(bg=elevation_1_color, fg=label_color)
        self.middle_frame.config(bg=bg_color)

        self.instructions_text_canvas.config(
            bg=elevation_1_color, borderwidth=1, relief="solid", highlightthickness=0
        )
        self.instructions_text_frame.config(bg=elevation_1_color)
        self.instructions_text.config(bg=elevation_1_color, fg=label_color)
        self.lower_frame.config(bg=bg_color)
        self.cost_label.config(bg=elevation_1_color, fg=label_color)
        self.cost_of_recipe_label.config(bg=elevation_1_color, fg=label_color)
        self.copy_text_button_image = Program.Program.create_rounded_button_image(
            bg_color,
            primary_color,
            Program.Program.convert_rgb_to_hex(
                Program.Program.overlay_colors(
                    Program.Program.convert_hex_to_rgb(primary_color),
                    Program.Program.convert_hex_to_rgb(button_text_color),
                    0.87,
                )
            ),
            "Copy Recipe",
            self.copy_text_button.winfo_width(),
            self.copy_text_button.winfo_height(),
            22,
        )
        self.copy_text_button.config(
            border="0",
            relief="flat",
            borderwidth=0,
            highlightthickness=0,
            activebackground=bg_color,
            image=self.copy_text_button_image,
        )
        self.back_button_image = Program.Program.create_rounded_button_image(
            bg_color,
            primary_color,
            Program.Program.convert_rgb_to_hex(
                Program.Program.overlay_colors(
                    Program.Program.convert_hex_to_rgb(primary_color),
                    Program.Program.convert_hex_to_rgb(button_text_color),
                    0.87,
                )
            ),
            "Back",
            self.back_button.winfo_width(),
            self.back_button.winfo_height(),
            22,
        )
        self.back_button.config(
            border="0",
            relief="flat",
            borderwidth=0,
            highlightthickness=0,
            activebackground=bg_color,
            image=self.back_button_image,
        )